home *** CD-ROM | disk | FTP | other *** search
/ The Whacked Mac Archives / The Whacked Mac Archives Version 1.0 (L0pht Heavy Industries, Inc.)(1996).iso / Pub (Expanded) / TextFiles / Mag_Stripes.txt < prev    next >
Text File  |  1994-12-26  |  25KB  |  521 lines

  1. Newsgroups: alt.2600
  2. Path: sundog.tiac.net!europa.eng.gtefsd.com!emory!swrinde!pipex!sunic!EU.net!uunet!iat.holonet.net!clafave
  3. From: clafave@iat.holonet.net (Christopher R LaFave)
  4. Subject: Re: Hacking aTM
  5. Message-ID: <CsCvt5.Lut@iat.holonet.net>
  6. Organization: HoloNet National Internet Access System: 510-704-1058/modem
  7. References: <2v5ev9$53p@lucy.infi.net>
  8. Date: Sun, 3 Jul 1994 08:34:16 GMT
  9. Lines: 510
  10.  
  11.              Magnetic stripe technology
  12.  
  13.  
  14. Figures and listings are at the end.
  15.  
  16.   Because of their widespread use, most magnetic cards adhere to well-defined
  17. standards that describe the physical and magnetic characteristics for a
  18. magnetic stripe on a plastic card. These standards outline specifications for a
  19. storage format and information interchange. This does not preclude other 
  20. encoding techniques or additional data tracks for specific applications, but in
  21. most cases it makes sense to adhere to at least the basic constraints. This
  22. gives you the choice of using any commercially available magnetic encoders for
  23. your application. The technique used for encoding magnetic cards is known as
  24. "Two-Frequency, Coherent Phase Recording". Allowing for the representation of
  25. single-channel, self-clocking serial data, this methodology is generally 
  26. referred to as F/2F. Self-clocking is achieved by combining data and clock bits
  27. together in a continuous, synchronous sequence. In this scheme, an intermediate
  28. flux transition signifies a one bit and the absence of an intermediate flux
  29. transition denotes a zero bit.
  30.   Three data tracks defined for use on standard magnetic cards each possess
  31. different bit densities and encoded character sets. The average bit density of
  32. track 1 is 210 bits per inch (bpi). Track 1 characters are made up of six data
  33. bits and an odd parity bit, encoded with the least-significant bit first and 
  34. the parity bit last, yielding a 64-character set. Taking the number of bits per
  35. inch and the number of bits per character, you can see track 1 has the capacity
  36. to hold 79 characters.
  37.   Track 2 has a bit density of 75 bpi, and track 3 uses 210 bpi. Both of these
  38. tracks allow the representation of a numeric-only character set. The characters
  39. for tracks 2 and 3 are encoded using a 4-bit binary-coded decimal subset with
  40. odd parity and, like track 1, are encoded with the least significant bit first
  41. and the parity bit last. The lower density of track 2 allows up to 40 numeric
  42. characters, where 107 numerics can be squeezed onto track 3. The actual number
  43. of usable characters will be fewer since you also have the Start Sentinel, End
  44. Sentinel, and LRC characters.
  45.   Though sometimes magnetic cards are moved past the read head mechanically,
  46. most applications rely on manually moving the card, either through a slotted
  47. reader or into an insertion-type reader. Typically the swipe rate is 5-20 inches
  48. per second (ips), with 50 ips being the fastest most card readers can handle. Of
  49. course, moving the card by hand will not only result in varying the absolute
  50. card velocity but, will also introduce incremental speed changes as the card
  51. accelerates and decelerates past the pickup. The F/2F scheme is very forgiving
  52. of such speed fluctuations. 
  53.   For all 3 tracks, the fundamental data format is similar and consists of the
  54. following elements: First, leading zero bits are encoded to indicate the 
  55. presence of an encoded magnetic card and provide synchronization pulses to the
  56. read head electronics and ultimately to the controller. Next, the Start Sentinel
  57. character is encoded which indicates the start of the actual data. The coded
  58. data follows. Next, the End Sentinel terminates the data portion of the card
  59. and followed by an LRC byte (used for error detection). The LRC is essentially
  60. a horizontal parity calculated by an exclusive-OR of all the data bits from the
  61. Start Sentinel to the End Sentinel (inclusive). Finally, trailing zeros follow
  62. the LRC and fill out the remainder of the card.
  63.               ANATOMY OF A MAGNETIC CARD
  64.   The magnetic tracks have inherent characteristics based on details such as 
  65. code set and bit and character densities. International organizations such as
  66. Mastercard and VISA impose additional constraits for their participating members
  67. and standards exist for bank debit cards and ATM cards as well. These rules
  68. specify the exact content and format of each data field in aech track as well as
  69. the intended uses for the tracks. Naturally, for nonfinancial uses, it is not
  70. necessary to comply with these standards. For dedicated uses such as access 
  71. control, people tracking, and material tracking, adhering to the minimal 
  72. standards is adequate.
  73.   The most-often-used track is track 2, although it offers the lowest inform-
  74. ation density of the three. It contains all the information that is normally
  75. used for credit card transactions. When a customer name is required, track 1
  76. must be used since it is the only track that permits alphanumeric data. Track 3
  77. is specified for numeric-only data, but is unique. It is intended for change-
  78. able data and consequently may not only be read but may be rewritten by the
  79. transaction-handling equipment. A multitude of data fileds are contained in
  80. these various tracks. Figure 1 shows a brief run-down of what is generally 
  81. placed on tracks 1 and 2.
  82.                   REAL CARD READERS
  83. The recovery of magnetically encoded F/2F data can be accomplished directly
  84. with the use of just about any microcontroller. There are no particular
  85. difficulties in deciphering the raw F/2F data stream and many early magnetic
  86. read heads contained nothing more than signal amplifiers and line drivers.
  87. These are now artifacts  since all modern magnetic read heads contain integ-
  88. rated F/2F bit recovery circuitry and interface with the host controller in a
  89. standard fashion using three wires: CARD PRESENT, CLOCK, and DATA. The read
  90. heads usually rely on a single chip to perform the linear signal conditioning,
  91. sychronization, and recovery of individual bits from the data stream. The Mag-
  92. Tek 21006505 IC is representative of this type of data recovery circuit and its
  93. functionality is depicted in figure 2.
  94.   Linear conditioning consists of raising the level of the magnetic pickup's
  95. input signal, rejecting common-mode noise, conditioning and detecting the 
  96. signal, and finally providing a digital output for susequent processing. The
  97. enable/disable counters provide initialization for the recovery section. The
  98. recovery section locks onto the data rate and recovers the individual data bits
  99. from the data stream. The oscillator section provides the clocks for the recov-
  100. ery section and for the enable/disable timers. Card present goes low after 8 or
  101. 9 flux reversals are seen from the magnetic pickup and will return high about
  102. 50 ms after the last flux reversal. The strobe line signals that data is valid
  103. and is active low. The data pin indicates a one bit when it is low. Raw F/2F
  104. data can also be picked directly off the chip.
  105.   The data rate for a high-density track scanned at 50 ips comes to 10500 bits
  106. per second (bps). This results in a transfer rate of 1500 characters per second
  107. for the 7-bit elements used on track 1, and 2100 characters per second using
  108. the 5-bit elements of track 3. I either case, this translates to a new bit 
  109. arriving at the controller just under every 100 us (microsecond). Even the most
  110. anemic controller should be able to keep up. With resonably good coding techni-
  111. ques, there should be no problem handling the entire data sampling phase on an
  112. interrupt-driven basis. The low-density (track 2) data flows at a more pedes-
  113. trian 3750 bps, yielding 750 5-bit characters per second, or a new bit every
  114. 266 us. Since most dual-track read heads provide track 1 and track 2 data, this
  115. indicates that handling both tracks simultaneously is feasible under interrupt
  116. control. Keep in mind that 50 ips is a rather fast scan rate; 20-30 ips is
  117. probably a more realistic limit.
  118.                  MAGNETIC BIT STORMS
  119.   When approaching a problem such as decoding magnetic cards, it pays to spend
  120. some time looking at the overall picture before starting to write the code. At
  121. first glance, it would seem that organizing the data into the prevailing element
  122. size during the sampling interval would make decoding easier. This could be
  123. easily done by ignoring all the leading zeros, with actual data storage comm-
  124. encing with the first one bit. Of course, this approach assumes you're getting
  125. good data. The fact that the data recovery is handled using well-proven hard-
  126. ware makes this assumption valid.
  127.   If all you need to do is decode the card in a forward direction, then going
  128. about things as I just described makes sense and reduces the coding effort to a
  129. trivial exercise. If you have to support reverse decoding then this is not the
  130. optimal solution. Having considered the tradeoffs of being able to decode a 
  131. magnetic card in both forward and reverse directions, I decided to structure the
  132. program to work equally well in either direction at the cost of a slight 
  133. increase in initial complexity. 
  134.   The first step in decoding is to acquire the serial bit stream. This can be 
  135. done using a dedicated sample loop or, with a little more work, using interrupt
  136. processing. Since the idea is the same regardless of the details, I decided to
  137. use a sample loop in my demonstration program (listing 1). The code simply
  138. records the incoming data stream and deposits the data in a sample buffer a byte
  139. at a time. Sampling begins when Card Present returns idle. Any incomplete byte
  140. that has been partially assembled at the time when sampling terminates is simply
  141. discarded. The abundance of leading and trailing zeros allows losing some bits
  142. at either end causing any problems. 
  143.   Once the sampling interval completes, control is transferred to the decoding
  144. algorithm. Presented in listing 2, the track-1 decode algorithm consists of 
  145. nothing more than some initialization and the essence of the decode logic.
  146. Limiting the gyrations contained in the main body of this routine not only makes
  147. the logic easy to follow, but permits the same code to handle the decoding in
  148. either a forward or reverse direction.
  149.   The initial entry point assumes a forward decode attempt and sets up the 
  150. necessary flags, pointers, and counters before jumping into the main initial-
  151. ization code. After initialization, the sample buffer is scanned for the first
  152. one bit, at which time a 7-bit element is assembled. If the parity is correct
  153. and the character code checks out to be a Start Sentinel, the code proceeds and
  154. starts pulling successive data elements from the sample buffer. If the data 
  155. element is not an End Sentinel, the character is translated to ASCII and stored
  156. in the decode buffer. Should an End Sentinel be detected, the program extracts
  157. the next character, which is assumed to be the LRC byte, and finally checks the
  158. calculated LRC for a value of zero.
  159.   The checks and balances included in the execution of this loop include things
  160. such as parity, a cumulative LRC, and checking to make sure I haven't run out of
  161. samples. If everything checks out, the program terminates and returns with the
  162. DPTR pointing to the decoded data buffer and the character count contained in
  163. ACC. Should a decode failure occur, a test is performed on the direction flag
  164. and if this is an attempt at a forward decode, the routine jumps to the reverse
  165. initialization entry point. The reverse entry is similar to the forward decode
  166. entry but sets up the sample pointer to the end of the sample buffer and sets 
  167. the direction flag to indicate a reverse operation.
  168.   The routines contained in the intermediate layer are shown in listing 3. The
  169. meaning and operation of these routines should be apparent. The key routine in
  170. this section is GET_BIT, which picks off the next bit from the sample buffer,
  171. essentially restoring the sequential nature of the initial magnetic bit stream.
  172. FIND_START is used to synchronize with the first one bit. GET_CHAR first checks
  173. to make sure it hasn't run out of samples, then assembles the next 7-bit data
  174. element while doing a parity test and LRC calculation. Any problems encountered
  175. here are sent back to the caller and are handled there. STORE_CHAR translates
  176. and deposits the data character into its respective location in the decoded-data
  177. buffer and increments the character counter.
  178.   Listing 4 shows the low-level code. These routines perform the most rudiment-
  179. ary functions and operate in accordance with the direction flag. INDEX_PTR 
  180. either increments or decrements the sample pointer, POSITION_BIT likewise does
  181. either a right or left shift and LOCATE_BIT returns the state of the least- or
  182. most- significant bit of the accumulator.
  183.                GO AHEAD, TAKE A SWIPE
  184.   Let me touch on a few additional points that may not be immediately apparent
  185. before signing off. Storing the sampled data in a continuous stream makes the
  186. sample routine work equally well with the various bit configurations used for
  187. the different recording tracks. This would not be easily attained if you tried
  188. to generate a particular element format during sample time. Furthermore, if you
  189. look at the differences between the encoded character sets and the bit formats
  190. for the different tracks, you will find that they differ in only a few areas.
  191. With a few minor changes, such as the defined Start Sentinel, number of bits per
  192. element, and character translation method, the decode routine I've shown could
  193. easily be coerced to handle the decoding of any of the standard magnetic tracks.
  194.   As a matter of fact, by recoding and redefining the hard-coded constants as
  195. variables, these could be set up for the particular data track at execution
  196. time before invoking the decode function. Doing so would not only save program
  197. memory, but would also allow you to use a routine you were comfortable with.  
  198.  
  199. *******************************************************************************
  200.                                    FIGURE 1
  201. _____________________________________________________________________
  202. TRACK 1 |SS|FC|   PAN   |FS|   NAME   |FS|  ADDITIONAL DATA  |ES|LRC|
  203. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  204. Notes: Track 1 is limited to 79 characters including SS, ES, and LRC.
  205. Mastercard PAN is variable up to 16 characters maximum. VISA is 13 or 16
  206.  characters, including mod-10 check digit. 
  207. SS: Start sentinel (%)
  208. FC: Format code 
  209. FS: Field separator ({)
  210. ES: End sentinel (?)
  211. LRC: Longitudinal redundency check character
  212. PAN (primary account number): 19 digits max.
  213. NAME: 26 alphanumeric characters max.
  214. ADDITIONAL DATA: Expiration date 4  
  215.          Restriction or type 3
  216.          Offset or PVN 5
  217. ______________________________________________________________________
  218. TRACK 2 |SS|FC|      PAN      |FS|       ADDITIONAL DATA      |ES|LRC|
  219. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  220. SS: Start sentinel (;) (hex B)
  221. FS: Field separator (=) (hex D)
  222. ES: End sentinel (?) (hex F)
  223. LRC: Longitudinal redundency check character
  224. PAN (primary account number): 19 digits max.
  225. ADDITIONAL DATA: Expiration date 4  
  226.          Restriction or type 3
  227.          Offset or PVN 5
  228.  
  229. *****************************************************************************
  230.                   FIGURE 2
  231. HEAD SIGNAL   __/~\__   __/~\__   __/~\__   __/~\__   __/~\__   __/~\_______
  232.              `-`       `-`       `-`       `-`       `-`       
  233. ____ _______  __________                                                ____
  234. CARD PRESENT            |______________________________________________|
  235.  
  236. ____ ____     _____________________      ____           ____           _____
  237. READ DATA                          |____|    |_________|    |_________|
  238.  
  239. ____ ______   __________    __   __   __   __   __   __   __   __   __   __
  240. READ STROBE             |__|  |_|  |_|  |_|  |_|  |_|  |_|  |_|  |_|  |_|  |
  241.  
  242.             |    0|   1|   0|   1|   1|   0|   1|   1|   0|   0|
  243.             
  244.  
  245.                                 ___ 
  246.                 HEAD 1-----X---X--------13 |MAG| 9--C2-R3
  247.                        R1  C1          |TEK|        |
  248.                 HEAD 2-----X---X--------12 |   | 10-----X--X
  249.                                |   |        |  |
  250.                          X---X------11 |   |        |  R5
  251.                     X-X      R2  C6        |   | 6------|--X
  252.                     | |      X---X-------8 |   |        | 
  253. +5VDC --------------X--R7--X--------X-|-----------------14 |   | 7-----C3
  254.             |      |+         |                    |   |       ____
  255.             R6     C5         |                    |   | 16----DATA
  256.             |      X----------|------------------5 |   |       ______
  257. ____ _______        |      |          X------------------2 |   | 15----STROBE
  258. CARD PRESENT -------X------|-----------------------------1 |   |
  259.                |                  X----X-----3 |   |
  260.                |                  C4   R4----4 |   |
  261. GND------------------------X------------------X            |___|
  262.  
  263. R=RESISTOR(Values weren't given)
  264. C=CAPACITOR(Values weren't given)
  265. X=CONNECTION BETWEEN WIRES
  266. MAG TEK is the Mag-Tek 21006505
  267.  
  268. *****************************************************************************
  269. LISTING 1-- Using several externally defined routines, a sample program to
  270.         read a stripe and store it in a buffer is very short.
  271.  
  272.         PUBLIC READ_MAG1
  273.         EXTERN MS1_BUF (XDATA)      ;sample buffer
  274.         EXTERN MS1_LIM (NUMBER)     ;sample limit
  275.         EXTERN MD1_BUF (XDATA)      ;decode buffer
  276.         EXTERN CP (BIT)             ;card present bit
  277.         EXTERN M1_CLK (BIT)         ;clock bit
  278.         EXTERN M1_DQ (BIT)          ;data bit  
  279.  
  280. M1_SS       EQU    5                    ;start sentinel
  281. M1_ES       EQU    1FH                  ;end sentinel
  282. ;
  283.         SEG    CODE
  284. ;Sample and decode magnetic track 1
  285. ; output: ACC contains character count.
  286. ;         DPTR points to data buffer
  287. READ_MAG1   PROC             
  288.         CALL   MAG_SAMPLE
  289.         JZ     L?RM1
  290.         CALL   MAG1_DECODE
  291. L?RM1:      RET
  292.         ENDPROC
  293. ;General-purpose magnetic sampling routine
  294. ; output: ACC contains sample count
  295. MAG_SAMPLE  PROC
  296.         MOV    DPTR,#MS1_BUF
  297.         MOV    R1,#0                ;sample counter
  298. L?MS1:      MOV    R0,#8                ;bit counter
  299. L?MS2:      JB     CP,L?MS4
  300.         JB     M1_CLK,L?MS2
  301.         MOV    C,M1_DQ
  302. L?MS3:      JB     CP,L?MS4            
  303.         JNB    M1_CLK,L?MS3
  304.         CPL    C
  305.         RRC    A
  306.         DJNZ   R0,L?MS2
  307.         MOVX   @DPTR,A
  308.         INC    DPTR
  309.         INC    R1                   ;sample counter
  310.         CJNE   R1,#MS1_LIM,L?MS1
  311. L?MS4:      MOV    A,R1                 ;final sample count
  312.         RET
  313.         ENDPROC
  314.         
  315. *******************************************************************************
  316. LISTING 2-- Once the serial bit stream has been acquired, the decoding
  317.         algorithm takes over.
  318.  
  319. ;Bidirectional magnetic track 1 decode routine
  320. ;input: sample count in ACC, output: ACC contains character count
  321. ;       DPTR points to decoded data buffer
  322. ;Reg. usage for this routine (includes subroutines) as follows:
  323. ;R5: Direction flag, 0=forward
  324. ;R4: Cumulative LRC register
  325. ;R3: Decoded character counter
  326. ;R2: Nondecrementing sample count
  327. ;R1: Decrementing sample count
  328. ;R0: Bit syncronizing counter
  329. MAG1_DECODE PROC
  330.         ;1st pass, setup for forward decode attempt
  331.         MOV    R5,#0                ;indicate forward decode
  332.         MOV    DPTR,#MS1_BUF        ;point to start of buffer
  333.         MOV    R1,A                 ;sample counter
  334.         MOV    R2,A                 ;sample count
  335.         JMP    L?M1D1                               
  336. L?M1D0:     ;2nd pass, setup for reverse decode attempt
  337.         MOV    R5,#1                ;indicate reverse decode
  338.         MOV    DPTR,#MS1_BUF
  339.         MOV    A,R2                 ;sample count
  340.         DEC    A
  341.         ADD    A,DPL
  342.         MOV    DPL,A
  343.         CLR    A
  344.         ADDC   A,DPH
  345.         MOV    DPH,A                ;point to end of buffer
  346.         MOV    R1,2                 ;sample counter
  347. L?M1D1:                                 ;decode initialization
  348.         MOV    R3,#0                ;character counter
  349.         MOV    R4,#0                ;inital LRC
  350.         MOV    R0,#0                ;bit syncronizer
  351.         CALL   FIND_START           ;main decode loop
  352.         JNC    L?M1D5               ;start bit error
  353.         CALL   GET_CHAR             ;Start Sentinel
  354.         JB     ACC.7,L?M1D5         ;format error
  355.         CJNE   A,#M1_SS,L?M1D5      ;start setinel error
  356. L?M1D2:                                 ;data byte or End Sentinel              
  357.         CALL   GET_CHAR
  358.         JB     ACC.7,L?M1D5         ;format error
  359.         CJNE   A,#M1_ES,L?M1D3      ;end sentinel not found
  360.         JMP    L?M1D4
  361. L?M1D3:                 
  362.         CALL   STORE_CHAR           ;data character
  363.         JMP    L?M1D2
  364. L?M1D4:                                 ;LRC
  365.         CALL   GET_CHAR             ;get LRC                        
  366.         JB     ACC.7,L?M1D5         ;format error
  367.         MOV    A,R4             
  368.         JNZ    L?M1D5               ;LRC error
  369.         MOV    DPTR,#MD1_BUF        ;good return
  370.         MOV    A,R3                 ;final character
  371.         RET
  372. L?M1D5:     ;decode error, check if 1st pass
  373.         CJNE   R5,#1,L?M1D0         ;check direction
  374.         CLR    A                    ;bad return
  375.         RET
  376.         ENDPROC
  377.  
  378. *******************************************************************************
  379. LISTING 3-- The intermediate layer of software is one level removed from the
  380.         nitty-gritty details.
  381.  
  382. ;Get the next bit from the sample buffer
  383. ;output: C contains data bit
  384. GET_BIT     PROC             
  385.         CJNE   R0,#0,L?GB1          ;bit synchronizer
  386.         MOV    R0,#8
  387.         PUSH   ACC
  388.         MOVX   A,@DPTR
  389.         CALL   INDEX_PTR
  390.         MOV    B,A
  391.         POP    ACC
  392.         DEC    R1                   ;sample counter
  393. L?GB1:      XCH    A,B
  394.         CALL   POSITION_BIT
  395.         XCH    A,B
  396.         DEC    R0                   ;bit synchronizer
  397.         RET
  398.         ENDPROC
  399. ;
  400. ;Find the first '1' bit in the sample buffer
  401. ;output: C=1 if bit is found
  402. FIND_START  PROC
  403. L?FS1:
  404.         CJNE   R0,#0,L?FS2          ;bit synchronizer
  405.         MOV    R0,#8                
  406.         MOVX   A,@DPTR
  407.         CALL   INDEX_PTR
  408.         DJNZ   R1,L?FS2             ;sample counter
  409.         JMP    L?FS4                ;out of samples
  410. L?FS2:      CALL   LOCATE_BIT           ;test for a '1' bit
  411.         JC     L?FS3          
  412.         CALL   POSITION_BIT                                         
  413.         DEC    R0                   ;bit synchronizer
  414.         JMP    L?FS1
  415. L?FS3:                                  ;good return
  416.         MOV    B,A                  ;save copy in B
  417.         SETB   C
  418.         RET
  419. L?FS4:      CLR    C                    ;bad return
  420.         RET
  421.         ENDPROC
  422. ;
  423. ;Get the next 7 bit element from the sample buffer
  424. ;output: ACC contains data element
  425. ;        error flag is ACC.7
  426. GET_CHAR    PROC                                
  427.         MOV    A,R1                 ;sample counter
  428.         JZ     L?GC2                ;out of samples
  429.         MOV    R7,#7                ;bit counter
  430.         CLR    A
  431. L?GC1:      CALL   GET_BIT              ;next bit
  432.         RRC    A                    
  433.         DJNZ   R7,L?GC1
  434.         RR         A
  435.         JNB    P,L?GC2              ;parity error
  436.         ANL    A,#3FH               ;discard parity
  437.         PUSH   ACC
  438.         XRL    A,R4                 ;calculate LRC
  439.         MOV    R4,A
  440.         POP    ACC                  ;good return
  441.         RET
  442. L?GC2:      SETB   ACC.7                ;bad return
  443.         RET
  444.         ENDPROC
  445. ;Translate and store the data character
  446. ;input: ACC contains data character
  447. STORE_CHAR  PROC
  448.         PUSH   DPL
  449.         PUSH   DPH 
  450.         PUSH   ACC
  451.         MOV    DPTR,#MD1_BUF
  452.         MOV    A,R3                 ;character counter
  453.         ADD    A,DPL
  454.         MOV    DPL,A
  455.         CLR    A
  456.         ADDC   A,DPH                ;generate displacement
  457.         MOV    DPH,A
  458.         POP    ACC
  459.         ADD    A,#' '               ;translate
  460.         MOVX   @DPTR,A              ;store
  461.         POP    DPH
  462.         POP    DPL
  463.         INC    R3                   ;character counter
  464.         RET
  465.         ENDPROC
  466.         
  467. *******************************************************************************
  468. LISTING 4-- The low-level routines get right down to the ground and take care
  469.         of the gory details.
  470.  
  471. ;Index the sample pointer either forward or backward
  472. INDEX_PTR          PROC
  473.         CJNE   R5,#0,L?IP1          ;check direction
  474.         INC    DPTR                 ;forward
  475.         RET
  476. L?IP1:      PUSH   ACC                  ;backward
  477.         DEC    DPL
  478.         MOV    A,DPL
  479.         CJNE   A,#-1,L?IP2
  480.         DEC    DPH
  481. L?IP2:      POP    ACC
  482.         RET
  483.         ENDPROC
  484.  
  485. ;Position bit is in ACC into C in either a right or left shift
  486. POSITION_BIT       PROC
  487.         CJNE   R5,#0,L?PB1          ;check direction
  488.         RRC    A                    ;forward
  489.         RET
  490. L?PB1:      RLC    A
  491.         RET
  492.         ENDPROC
  493.         
  494. ;Locate a 1 bit, either msb or lsb
  495. ;output: C=1 if bit is a one
  496. LOCATE_BIT         PROC
  497.         CJNE   R5,#0,L?LB1          ;check direction
  498.         MOV    C,ACC.0              ;forward
  499.         RET
  500. L?LB1:      MOV    C,ACC.7              ;backward
  501.         RET
  502.         ENDPROC
  503.         
  504. *******************************************************************************
  505. Contact:
  506.  Mag-Tek, Inc.
  507.  20725 S. Annalee Ave.
  508.  Carson, CA 90746
  509.  (213) 631-8602
  510.  fax: (213) 631-3956
  511. *******************************************************************************
  512.  
  513.  
  514.  
  515.  
  516. -- 
  517.                _
  518.   __ |   __   | ` __      __   clafave@holonet.net
  519.  |   |   __| ~|~  __||  ||__|  Beaverton, Oregon USA
  520.  |__ |_ |__|  |  |__| \/ |__.  GO BLAZERS!
  521.